Expansion Activities

The modifications performed by the expander are tree transformations that must be applied to those Ada constructs that do not have a close equivalent in C, such as allocators, aggregates, tagged types and dynamic dispatching, and all aspects of the tasking. The expansion phase also simplifies some aspects of semantic analysis which are awkward to perform strictly in one pass, eg. the correct handling of the private part of a package declaration. The most important expansions are the following;

  1. Construction of initialization procedures for record and array types, and invocation of these procedures for each object of such a type. This is also done for tasks and protected objects.

  2. Generic instantiation. Instantiation is always done in-line, so that declaration and body of the instance are inserted into the AST at the point of instantiation.

  3. All tasking operations are transformed into calls to subprograms in the run-time system. The recursive mechanisms of GNAT are particularly useful here. For example, consider operations on the attribute <#467#>COUNT<#467#>. The run-time holds the specification of a run-time function that examines the corresponding queue. Rather than including the details of such a function in the compiler proper, the run-time package is analyzed by the compiler as if it had appeared in the context clause of the current compilation. If the function is subject to an <#468#>INLINE<#468#> pragma, the compiler can perform the inlining as well, without forcing the compiler to have detailed information about the run-time, and without affecting code quality. Such flexibility cannot be achieved with a more conventional compiler organization. Because of the speed of the compiler, the cost of this approach in terms of space and time is comparable or cheaper than the conventional approach.